/*
 * Copyright [2011] [Pettersen Consulting]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *  
 *   http://www.apache.org/licenses/LICENSE-2.0
 *  
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.   
 */
package com.edb.os.xstream;

import java.io.Writer;
import java.util.Stack;

import com.edb.os.xstream.writer.ClassWriter;
import com.thoughtworks.xstream.io.ExtendedHierarchicalStreamWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

/**
 * @author Oystein Pettersen
 *
 */
public class JavaWriter implements ExtendedHierarchicalStreamWriter {

    private final Writer writer;

    private Stack<ClassWriter> stack;
    private int currentDepth = 0;
    private int paramNameIndex = 0;
    private ClassWriter currentParent = null;
    private ClassWriterFactory classWriterFactory;

    public JavaWriter(Writer writer, ClassWriterFactory classWriterFactory) {
        this.writer = writer;
        stack = new Stack<ClassWriter>();
        this.classWriterFactory = classWriterFactory;
    }
    
    public JavaWriter(Writer writer) {
        this(writer, new ClassWriterFactory());
    }
    
    /* (non-Javadoc)
     * @see com.thoughtworks.xstream.io.HierarchicalStreamWriter#startNode(java.lang.String)
     * 
     * This gets called with special stuff such as the inner list for a list implementation
     */
    public void startNode(String name) {
        // get the current parent to create the correct class writer for this element
        ClassWriter childWriter = currentParent.createChildWriter(name, currentDepth++);
        stack.add(childWriter);
    }

    public void addAttribute(String name, String value) {
        System.out.println("addAttribute - name: " + name + " value: " + value);
    }

    public void setValue(String text) {
        ClassWriter dataClass = stack.peek();
        dataClass.setValue(text);
    }

    public void endNode() {
        currentDepth--;
        ClassWriter poppedElement = stack.pop();

        // check if we are at the top
        if (stack.isEmpty()) {
            currentParent = null;

            // write the return statement
            poppedElement.writeReturnStatement(writer);
        } else {
            // check if the pop results to moving up one level, if so set a new current parent
            // if the next item on the stack as a different index then we are moving up, so set the parent to the next level
            if (poppedElement.depthIndex() != stack.peek().depthIndex()) {
                currentParent = stack.peek();
            }

            currentParent.add(poppedElement, writer);
        }
    }

    public void flush() {
    }

    public void close() {
    }

    public HierarchicalStreamWriter underlyingWriter() {
        return null;
    }

    @SuppressWarnings("rawtypes")
    public void startNode(String name, Class clazz) {

        ClassWriter classWriter;
        
        // determine the type of class provided
        // set initial parent if first run
        if (stack.isEmpty()) {
            classWriter = classWriterFactory.create(name, clazz, currentDepth, paramNameIndex++);
            currentParent = classWriter;
        }
        else {
            classWriter = currentParent.createChildWriter(name, clazz, currentDepth, paramNameIndex);
        }

        stack.push(classWriter);
        currentDepth++;
        paramNameIndex++;

        // inform the writer that it has been located. It is up to it if it needs to write something (like new) to the writer
        classWriter.create(writer);
    }  
}
